package show.me.the.money.config.schema;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;

import show.me.the.money.config.DocConfig;
import show.me.the.money.config.SortComparator;
import show.me.the.money.config.Sortable;

@SuppressWarnings("unchecked")
public class Schema extends DocConfig{
	private static Log logger = LogFactory.getLog(Schema.class);
	private static String[] relAlias = {"b","c","d","e","f","g","h","i"};
	private HashMap<String,SchemaItem> items = new LinkedHashMap<String,SchemaItem>();
	private List<SchemaRelation> parents = new ArrayList<SchemaRelation>();
	private List<SchemaRelation> children = new ArrayList<SchemaRelation>();
	private String alias;
	private String key;
	private String sortInfo;
	private String keyGenerator;
	private String tableName;
	
	public String getTableName() {
		return tableName;
	}
	
	
	public void setDefineDoc(Document doc){
		super.setDefineDoc(doc);
		
		if(defineDoc == null){
			logger.error("init schema[" + id + "]failed");
			return;
		}
		Element define = defineDoc.getRootElement();
		//parse base info
		tableName = define.attributeValue("tableName",id);
		alias = define.attributeValue("alias",id);
		Element ke = (Element)define.selectSingleNode("item[@pkey='true']");
		if(ke != null){
			key = ke.attributeValue("id");
			keyGenerator = ke.attributeValue("generator","auto");
		}
		sortInfo = define.attributeValue("sort",key);
		//parse relations
		List<Element> els = define.selectNodes("relations/relation");
		int count = 0;
		for(Element rel : els){
			String type = rel.attributeValue("type","children");
			String entryName = rel.attributeValue("entryName");
			String alias = relAlias[count];
			SchemaRelation sr = new SchemaRelation(type,entryName,alias);
			if(type.equals("parent")){
				parents.add(sr);
				Schema psc = SchemaController.instance().getSchema(entryName);
				String fk = psc.getKey().getId();
				if(rel.element("join") == null){
					sr.addJoinCondition(fk, fk);
				}
			}
			else{
				children.add(sr);
				if(rel.element("join") == null){
					sr.addJoinCondition(key, key);
				}
			}
			els = rel.elements("update");
			for(Element update : els){
				sr.addUpdate(update.attributeValue("from"), update.attributeValue("to"), update.attributeValue("func",""));
			}
			els = rel.elements("join");
			for(Element join : els){
				sr.addJoinCondition(join.attributeValue("parent"), join.attributeValue("child"));
			}
			count ++;
		}			
		//parse items
		els = define.elements("item");
		int index = 0;
		for(Element el : els){
			String id = el.attributeValue("id");
			String ref = el.attributeValue("ref");
			if(StringUtils.isEmpty(ref)){
				SchemaItem item = new SchemaItem(el,index);
				items.put(id, item);
			}
			else{
				int n = ref.indexOf(".");
				String rEntryAlias = "b";
				String rItemId = ref;
				if(ref.indexOf(".") > -1){
					rEntryAlias = ref.substring(0,n);
					rItemId = ref.substring(n + 1);
				}
				SchemaRelation sr = getRelationByAlias(rEntryAlias);
				if(sr != null){
					Schema sc = sr.getEntrySchema();
					SchemaItem fi = sc.item(rItemId);
					if(fi != null){
						Element refE = fi.defineXML();
						List<Attribute> attrs = el.attributes();
						for(Attribute attr : attrs){
							refE.addAttribute(attr.getName(), attr.getText());
						}
						SchemaItem item = new SchemaItem(refE,index);
						item.setProperty("refAlias",rEntryAlias);
						items.put(ref, item);
					}
				}
			}
			index ++;
		}

	}
	
	public String getSortInfo(){
		return sortInfo;
	}
	
	public SchemaItem item(String id){
		if(items.containsKey(id)){
			return items.get(id);
		}
		return null;
	}
	
	public SchemaItem getKey(){
		return items.get(key);
	}
	
	public String getAlias(){
		return alias;
	}	
	
	public HashMap<String,SchemaItem> getAllItems(){
		return items;
	}
	
	public List<SchemaItem> getAllItemsList(){
		Comparator<Sortable> c = new SortComparator();
		List<SchemaItem> ls = new ArrayList<SchemaItem>();
		ls.addAll(items.values());
		Collections.sort(ls,c);
		return ls;
	}
	
	public List<SchemaRelation> getParentRelations(){
		return parents;
	}
	
	public SchemaRelation getRelationByAlias(String a){
		for(SchemaRelation  r :  parents){
			if(r.getAlias().equals(a)){
				return r;
			}
		}
		for(SchemaRelation  r :  children){
			if(r.getAlias().equals(a)){
				return r;
			}
		}
		return null;
	}

	public List<SchemaRelation> getChildRelations(){
		return children;
	}	
	
	public HashMap<String,Object> data(){
		HashMap<String,Object> h = new HashMap<String,Object>();
		h.put("id", id);
		h.put("alias", alias);
		List items = new ArrayList();
		
		h.put("pkey", key);
		h.put("keyGenerator", keyGenerator);
		h.put("items", items);

		
		List<SchemaItem> c =  getAllItemsList();
		for(SchemaItem si:c){
			HashMap<String,Object> j = si.data();
			items.add(j);
		}
		return h;
	}
	
	
}
